package com.heima.utils.common;


import java.util.*;

public class SensitiveWordUtil {
    public static Map<String, Object> dictionaryMap = new HashMap<>();
    /**
     * 生成关键词字典库
     *
     * @param words
     * @return
     */
    public static void initMap(Collection<String> words) {
        if (words == null) {
            System.out.println("敏感词列表不能为空");
            return;
        }
        // map初始长度words.size()，整个字典库的入口字数(小于words.size()，因为不同的词可能会有相同的首字)
        Map<String, Object> map = new HashMap<>(words.size());
        // 遍历过程中当前层次的数据
        Map<String, Object> curMap = null;
        Iterator<String> iterator = words.iterator();
        //遍历
        while (iterator.hasNext()) {
            //获得集合中的一个词
            String word = iterator.next();
            curMap = map;  //这里是把map的地址赋值给了curMap
            int len = word.length();
            for (int i = 0; i < len; i++) {
                // 遍历每个词的所有字
                String key = String.valueOf(word.charAt(i));
                // 当前字在当前层是否存在, 不存在则新建, 当前层数据指向下一个节点, 继续判断是否存在数据
                Map<String, Object> wordMap = (Map<String, Object>) curMap.get(key);
                if (wordMap == null) {
                    // 每个节点存在两个数据: 下一个节点和isEnd(是否结束标志)
                    wordMap = new HashMap<>(2);
                    wordMap.put("isEnd", "0");
                    curMap.put(key, wordMap);  //因为curMap的内存地址指向了map,所以map得到了这里的key和wordMap
                }
                curMap = wordMap;  //这里是把wordMap的内存地址赋值给了curMap  因此每次循环,都会嵌套一层wordMap到上一层的curMap
                // 如果当前字是词的最后一个字，则将isEnd标志置1
                if (i == len - 1) {
                    curMap.put("isEnd", "1");
                }
            }
        }
        dictionaryMap = map;
    }
    /**
     * 搜索文本中某个文字是否匹配关键词
     *
     * @param text
     * @param beginIndex
     * @return
     */
    private static int checkWord(String text, int beginIndex) {
        if (dictionaryMap == null) {
            throw new RuntimeException("字典不能为空");
        }
        boolean isEnd = false;
        int wordLength = 0;
        Map<String, Object> curMap = dictionaryMap;
        int len = text.length();
        // 从文本的第beginIndex个字开始匹配
        for (int i = beginIndex; i < len; i++) {
            String key = String.valueOf(text.charAt(i));
            // 获取当前key的下一个节点
            curMap = (Map<String, Object>) curMap.get(key);
            if (curMap == null) {
                break;
            } else {
                wordLength++;
                if ("1".equals(curMap.get("isEnd"))) {
                    isEnd = true;
                }
            }
        }
        if (!isEnd) {
            wordLength = 0;
        }
        return wordLength;
    }
    /**
     * 获取匹配的关键词和命中次数
     *
     * @param text
     * @return
     */
    public static Map<String, Integer> matchWords(String text) {
        Map<String, Integer> wordMap = new HashMap<>();
        int len = text.length();
        for (int i = 0; i < len; i++) {
            //搜索文本中某个文字是否匹配关键词,并返回匹配到的数量
            int wordLength = checkWord(text, i);
            if (wordLength > 0) {
                //每次截取一个字
                String word = text.substring(i, i + wordLength);
                // 添加关键词匹配次数
                if (wordMap.containsKey(word)) {
                    //已经存在,则获取当前字的匹配次数并+1
                    wordMap.put(word, wordMap.get(word) + 1);
                } else {
                    //没有的话创建这个字,匹配次数为1
                    wordMap.put(word, 1);
                }
                i += wordLength - 1;
            }
        }
        return wordMap;
    }
    //测试
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("法轮");
        list.add("冰毒");
        list.add("法海");
        list.add("不懂爱");
        initMap(list); // 将敏感词列表封装成DFA结构

        String content = "我是一个好人，并不会卖冰毒，也不操练法轮功,我真的不卖冰毒";  //法轮=1, 冰毒=2
        Map<String, Integer> map = matchWords(content); // 检查敏感词
        System.out.println(map);
    }
}
